package tum0r.webengine.extension

import com.alibaba.fastjson.JSON
import java.lang.reflect.Field

/**
 * 说明: 反射扩展
 *
 * 创建者: tum0r
 *
 * 时间: 2021/10/29 14:24
 */

/**
 * 获取某一对象的某一字段的值
 *
 * @param[targetObject] 对象
 */
fun <T> Field?.getObjectValue(targetObject: T?): Any? {
    return if (this == null || targetObject == null) null
    else {
        val flag = this.canAccess(targetObject)
        this.isAccessible = true
        val result = this.get(targetObject)
        this.isAccessible = flag
        result
    }
}

/**
 * 设置某一对象的某一字段的值
 *
 * @param[targetObject] 对象
 * @param[value] 字段的值
 */
fun <T> Field?.setObjectValue(targetObject: T, value: Any?) {
    if (this == null) return
    val flag = this.canAccess(targetObject)
    this.isAccessible = true
    when (value) {
        is String? -> this.set(targetObject, value)
        else -> this.set(targetObject, JSON.parseObject(value.toString(), this.type))
    }
    this.isAccessible = flag
}

/**
 * 获取类和继承的类以及实现的接口中的所有属性，并按照类为键，属性集合为值的结果返回
 *
 * @param[justPublic] 是否只需要public的属性
 */
@JvmOverloads
fun Class<*>.getAllFieldsWithClass(justPublic: Boolean = false): LinkedHashMap<Class<*>, ArrayList<Field>> {
    val result = LinkedHashMap<Class<*>, ArrayList<Field>>()
    var targetClass: Class<*>? = this
    while (targetClass != null) {
        val item = ArrayList<Field>()
        if (justPublic)
            item.addAll(targetClass.fields)
        else
            item.addAll(targetClass.declaredFields)
        if (item.size != 0 && !result.containsKey(targetClass))
            result[targetClass] = item
        for (interfaceClass in targetClass.interfaces)
            for (temp in interfaceClass.getAllFieldsWithClass(justPublic))
                if (!result.containsKey(temp.key))
                    result[temp.key] = temp.value
        targetClass = targetClass.superclass
    }
    return result
}

/**
 * 获取类和继承的类以及实现的接口中的所有属性
 *
 * @param[justPublic] 是否只需要public的属性
 */
@JvmOverloads
fun Class<*>.getAllFields(justPublic: Boolean = false): ArrayList<Field> {
    val result = ArrayList<Field>()
    for (fields in this.getAllFieldsWithClass(justPublic).values)
        result.addAll(fields)
    return result
}